import {
  ATTR,
  TEXT,
  REMOVE,
  REPLACE
} from './patchTypes';

let patches = {},
  vnIndex = 0;

/**
 * patches格式：
 * {
 *   0: [
 *        {
 *          //属性更改了
 *          type: 'ATTR',
 *          attr: 'list-wrap'
 *        }
 *   ],
 *   2: [
 *        {
 *          type: 'ATTR',
 *          attr: 'title'
 *        }
 *   ],
 *   6: [
 *        {
 *          type: 'REMOVE',
 *          index: 6
 *        }
 *    ],
 *   7: [
 *        {
 *          type: 'REPLACE',
 *          newNode: newNode
 *        }
 *   ]
 * }
 */

/**
 * 新老虚拟节点对比
 * @param {*} oldVDom 
 * @param {*} newVDom 
 * @returns 返回一个补丁
 */
function domDiff(oldVDom, newVDom) {
  let index = 0;

  //walk命名：一般用于底层封装程序遍历或者递归过程
  //深度遍历嵌套节点
  vNodeWalk(oldVDom, newVDom, index);


  //返回一个补丁
  return patches;
}

/**
 * 根据标签/标签属性/文本节点/移除节点时打入补丁的函数
 * @param {*} oldNode 
 * @param {*} newNode 
 * @param {*} index 
 */
function vNodeWalk(oldNode, newNode, index) {
  //自身的patch
  let vnPatch = [];

  //没有新的节点时才可以将对象放入自身补丁数组里
  if (!newNode) {
    vnPatch.push({
      type: REMOVE,
      index: index
    });
  } else if (typeof oldNode === 'string' && typeof newNode === 'string') {
    //文本节点的情况下是字符串
    //如果文本内容一样的不做操作
    //如果文本内容不一样就打补丁
    if (oldNode !== newNode) {
      vnPatch.push({
        type: TEXT,
        text: newNode
      });
    }
  } else if (oldNode.type === newNode.type) {
    //标签一样时有可能里面的属性不一样
    //拿到新老标签属性对比的补丁
    const attrPatch = attrsWalk(oldNode.props, newNode.props);

    /**
     * console.log(attrPatch);
     * {class: 'list-wrap', style: undefined}
     */

    // console.log(Object.keys(attrPatch));
    //['class', 'style']

    if (Object.keys(attrPatch).length > 0) {
      //证明数组里有内容
      //给属性打补丁
      vnPatch.push({
        type: ATTR,
        attrs: attrPatch
      });
    }

    //遍历子节点
    childrenWalk(oldNode.children, newNode.children);
  } else {
    //替换标签名的情况下
    //打补丁
    vnPatch.push({
      type: REPLACE,
      newNode: newNode
    });
  }

  //补丁容器里有补丁时
  if (vnPatch.length > 0) {
    patches[index] = vnPatch;
  }

}

/**
 * 遍历对比标签里新老属性
 * @param {*} oldAttrs 
 * @param {*} newAttrs 
 * @return 返回新老标签属性对比的补丁
 */
function attrsWalk(oldAttrs, newAttrs) {
  let attrPatch = {};

  //遍历老的属性
  for (let key in oldAttrs) {
    //修改属性
    //当新老的属性值不一样时
    if (oldAttrs[key] !== newAttrs[key]) {
      //打补丁到attrPatch对象里
      attrPatch[key] = newAttrs[key];
    }
  }

  //遍历新的属性
  for (let key in newAttrs) {
    //增加属性
    //如果老的属性里没有自身属性时
    if (oldAttrs.hasOwnProperty(key)) {
      attrPatch[key] = newAttrs[key];
    }
  }

  return attrPatch;

}

/**
 * 遍历新老子节点
 * @param {*} oldChildren 
 * @param {*} newChildren 
 */
function childrenWalk(oldChildren, newChildren) {
  oldChildren.map((c, idx) => {
    //递归
    vNodeWalk(c, newChildren[idx], ++vnIndex);
  });
}

export default domDiff;